#pragma once

#include "Framework.h"
#include "Math.h"

namespace Framework
{
	class Vector2;
	class _HELIX_FRAMEWORK_ITEM Vector3
	{
	public:
		Vector3() : x(0), y(0), z(0) {}
		Vector3(float x, float y, float z);
		Vector3(Vector2& vector, float z);
		Vector3(const Vector3& vector);
		~Vector3();
		void Normalize();
		float Length();
		float SqrLength();
		Vector3 Cross(Vector3& other);
		friend Vector3 operator + (const Vector3& a, const Vector3& b) { return Vector3(a.x+b.x, a.y+b.y, a.z+b.z); }
		friend Vector3 operator - (Vector3& a, Vector3& b) { return Vector3(a.x-b.x, a.y-b.y, a.z-b.z); }
		friend Vector3 operator * (Vector3& a, const float f) { return Vector3(a.x*f, a.y*f, a.z*f); }
		friend Vector3 operator * (const float f, Vector3& a) { return Vector3(a.x*f, a.y*f, a.z*f); }
		friend Vector3 operator * (Vector3& a, Vector3& b) { return Vector3(a.x*b.x, a.y*b.y, a.z*b.z); }
		friend Vector3 operator / (Vector3& a, const float f) { return Vector3(a.x/f, a.y/f, a.z/f); }
		friend Vector3 operator / (Vector3& a, Vector3& b) { return Vector3(a.x/b.x, a.y/b.y, a.z/b.z); }
		Vector3 operator - () const { return Vector3(-x, -y, -z); }
		static float Dot(Vector3& a, Vector3& b);
		static float Length(Vector3& vector);
		static float SqrLength(Vector3& vector);
		static Vector3 Cross(Vector3& a, Vector3& b);
		static void Normalize(Vector3& vector);
		static Vector3 BaryCentric(Vector3& a, Vector3& b, Vector3& c, float b1, float b2);
		static Vector3 UnitX;
		static Vector3 UnitY;
		static Vector3 UnitZ;
		static Vector3 Null;
		union
		{
			struct { float x, y, z; };
			struct { float cell[3]; };
		};
	};

	inline float Vector3::Dot(Vector3 &a, Vector3 &b)
	{
		return a.x*b.x + a.y*b.y + a.z * b.z;
	}

	inline Vector3 Vector3::Cross(Vector3& a, Vector3& b)
	{
		Vector3 out;
		out.x = (a.y * b.z) - (a.z * b.y);
		out.y = (a.z * b.x) - (a.x * b.z);
		out.z = (a.x * b.y) - (a.y * b.x);
		return out;
	}

	inline float Vector3::Length(Vector3& vector)
	{
		float l = SqrLength(vector);
		return (float)Math::Sqrt((double)l);
	}

	inline float Vector3::SqrLength(Vector3& vector)
	{
		return Dot(vector, vector);
	}

	inline void Vector3::Normalize(Vector3& vector)
	{
		float length = 1.0f / Length(vector);
		vector.x *= length;
		vector.y *= length;
		vector.z *= length;
	}

	inline Vector3 BaryCentric(Vector3& a, Vector3& b, Vector3& c, float b1, float b2)
	{
		Vector3 out;
		out = (a + ((b - a) * b1)) + ((c - a) * b2);
		return out;
	}
};